package com.lungolago.bank.services.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

import org.primefaces.component.inputtext.InputText;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.lungolago.bank.dao.UserDao;
import com.lungolago.bank.domain.UserEntity;
import com.lungolago.bank.services.UserService;

/**
 * Service providing service methods to work with user data and entity.
 * @author Franco
 */
public class UserServiceImpl implements UserService, UserDetailsService{

	private UserDao userDao;
	
	/**
	 * Create user - persist to db
	 * 
	 * @param userEntity
	 * @return true if success
	 */
	public boolean createUser(UserEntity userEntity) {
		//Logic to check if userName is available or not taken
		if(userDao.checkAvailability(userEntity.getUserName())){
			try {
				userDao.save(userEntity);
			} catch(Exception e){
				FacesMessage faceMsg = constructFatalMessage(e.getMessage(), null);
				getFacesContext().addMessage(null, faceMsg);
				return false;
			}
			
			return true;
		}else{
			//Need to set an error Messages to PrimeFaces component
			FacesMessage faceMsg = constructErrorMessage(String.format("User Name '%s' is not "
					+ "available", userEntity.getUserName()), null);
			getFacesContext().addMessage(null, faceMsg);
			return false;
		}
	}
	
	/**
	 * Check user name availability. UI ajax use.
	 * Invoked from signUp.xhtml
	 * 
	 * @param ajax event
	 * @return
	 */
	public boolean checkAvailability(AjaxBehaviorEvent event) {
		//org.primefaces.component.inputtext.InputText;
		InputText inputText = (InputText) event.getSource();
		String value = (String) inputText.getValue();
		
		boolean available = userDao.checkAvailability(value);
		
		if (!available) {
			FacesMessage message = constructFatalMessage(null, String.format(getMessageBundle().getString("userExistsMsg"), value));
			getFacesContext().addMessage(event.getComponent().getClientId(), message);
		} else {
			FacesMessage message = constructInfoMessage(null, String.format(getMessageBundle().getString("userAvailableMsg"), value));
			getFacesContext().addMessage(event.getComponent().getClientId(), message);
		}
		
		return available;
	}
	
	/**
	 * Construct UserDetails instance required by spring security (enforced by 
	 * UserDetailsService Interface)
	 */
	public UserDetails loadUserByUsername(String userName)
			throws UsernameNotFoundException {
		
		UserEntity user = userDao.loadUserByUserName(userName);
		
		if (user == null){
			throw new UsernameNotFoundException(String.format("No such user with that fucking user name provided '%s'", userName));
		}
		
		Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
		
		//org.springframework.security.core.userdetails.User
		User userDetails = new User(userName, user.getPassword(), authorities);
		return userDetails;
	}
	
	//Utility Methods
	protected FacesMessage constructErrorMessage (String message, String detail){		
		return new FacesMessage(FacesMessage.SEVERITY_ERROR, message, detail);
	}
	
	protected FacesMessage constructInfoMessage (String message, String detail){		
		return new FacesMessage(FacesMessage.SEVERITY_INFO, message, detail);
	}
	
	protected FacesMessage constructFatalMessage (String message, String detail){		
		return new FacesMessage(FacesMessage.SEVERITY_FATAL, message, detail);
	}
	
	protected FacesContext getFacesContext() {
		return FacesContext.getCurrentInstance();
	}
	
	protected ResourceBundle getMessageBundle() {
		return ResourceBundle.getBundle("message-labels");
	}

	//Getters and Setters
	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

}
